package com.qipay.admin.withdraw.controller;

import com.qipay.admin.BaseController;
import com.qipay.admin.tags.PageModel;
import com.qipay.admin.withdraw.config.BwmConfig;
import com.qipay.admin.withdraw.service.WithdrawAnotherService;
import com.qipay.admin.withdraw.service.WithdrawLogicService;
import com.qipay.admin.withdraw.vo.CountWithdrawInfoVo;
import com.qipay.admin.withdraw.vo.WithdrawExportVo;
import com.qipay.admin.withdraw.vo.WithdrawVo;
import com.qipay.baas.model.Cp;
import com.qipay.baas.model.CpWithdrawTradlog;
import com.qipay.core.help.ResultHelper;
import com.qipay.cp.CpService;
import com.qipay.excel.service.ExcelService;
import com.qipay.excel.service.ExcelUtils;
import com.qipay.holiday.service.HolidayService;
import com.qipay.security.UserDetailsServiceImpl;
import com.qipay.sms.config.AliyunSMSTemplateEnum;
import com.qipay.sms.utils.CodeCacheUtils;
import com.qipay.sp.SpConfigService;
import com.qipay.user.entity.UserLevel;
import com.qipay.utils.DateUtils;
import com.qipay.utils.Result;
import com.qipay.withdraw.config.WithdrawStateEnum;
import com.qipay.withdraw.service.WithdrawService;
import io.jsonwebtoken.lang.Assert;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;


/**
 * Creator: Yao
 * Date:    2017/9/27
 * For:
 * Other:
 */
@Controller
@RequestMapping("/withdraw")
public class WithdrawController extends BaseController {

    @Autowired
    WithdrawLogicService withdrawLogicService;

    @Autowired
    WithdrawAnotherService withdrawAnotherService;
    @Autowired
    HolidayService holidayService;

    private String msg;

    @Autowired
    WithdrawService withdrawService;
    @Autowired
    ExcelUtils excelUtils;
    @Autowired
    CodeCacheUtils codeCacheUtils;
    @Autowired
    CpService cpService;
    @Autowired
    SpConfigService spConfigService;


    private final static String pattern = "\\d{4}-\\d{1,2}-\\d{1,2}";


    @RequestMapping(value = {"", "/", "/cp", "/admin"}, method = RequestMethod.GET)
    public ModelAndView listByCpId(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @RequestParam(value = "cpId", required = false, defaultValue = "") Long cpId,
            @RequestParam(value = "state", required = false, defaultValue = "") Byte state,
            @RequestParam(value = "from", required = false, defaultValue = "") String from,
            @RequestParam(value = "to", required = false, defaultValue = "") String to,
            @RequestParam(value = "p", required = false, defaultValue = "1") int p,
            @RequestParam(value = "pz", required = false, defaultValue = "10") int pz) throws ParseException, UnsupportedEncodingException {

        // check
        Assert.notNull(loginUser);
        UserLevel level = loginUser.getLevel();
        List<WithdrawVo> lst = null;
        PageModel pageModel = new PageModel();
        long total = 0;
        CountWithdrawInfoVo countWithdrawInfoVo = null;
        p = p < 1 ? 1 : p;
        pz = pz <= 0 ? 10 : pz;

        // init
        ModelAndView view = createModelAndView("withdraw-lst");
        to = DateUtils.checkElseNow(to);
        if (StringUtils.isNotBlank(from)) {
            Assert.isTrue(from.matches(pattern), "指定开始日期格式有误，非 YYYY-MM-DD 形式");
        } else {
            from = to;
        }

        // query

        if (!level.equals(UserLevel.ADMIN)) {
            cpId = Long.valueOf(loginUser.getUsername());
        }
        total = withdrawLogicService.count(cpId,state, from, to);
        if (total > 0) {
            lst = withdrawLogicService.list(cpId,state, from, to, p, pz);
        }
        //统计行信息
        countWithdrawInfoVo = withdrawLogicService.countInfo(cpId,state, from, to);
        // url.init
        String url = "?";
        if (StringUtils.isNotBlank(from)) {
            url += String.format("&from=%s", URLEncoder.encode(from, "utf8"));
        }
        if (StringUtils.isNotBlank(to)) {
            url += String.format("&to=%s", URLEncoder.encode(to, "utf8"));
        }
        if (cpId != null) {
            url += String.format("&cpId=%s", URLEncoder.encode(cpId.toString(), "utf8"));
        } if (state != null) {
                url += String.format("&state=%s", URLEncoder.encode(state.toString(), "utf8"));

        }
        if (!"?".equalsIgnoreCase(url)) {
            pageModel.setUrl(url);
        }

        // fill
        withdrawLogicService.initConfig(view, loginUser);
        view.addObject("total", total);
        view.addObject("lst", lst);
        view.addObject("level", level);
        view.addObject("from", from);
        view.addObject("to", to);
        view.addObject("cpId", cpId);
        view.addObject("state", state);
        view.addObject("states", mapState());
        view.addObject("countWithdrawInfoVo", countWithdrawInfoVo);
        pageModel.setPage(p);
        pageModel.setPageSize(pz);
        pageModel.setTotal(total);
        view.addObject("page", pageModel);

        return view;
    }

    @Autowired
    ExcelService excelService;
    //导出
    @RequestMapping(value = "/export", method = RequestMethod.GET)
    public String export(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @RequestParam(value = "cpId", required = false, defaultValue = "") Long cpId,
            @RequestParam(value = "state", required = false, defaultValue = "") Byte state,
            @RequestParam(value = "from", required = false, defaultValue = "") String from,
            @RequestParam(value = "to", required = false, defaultValue = "") String to,
            HttpServletResponse resp
    ) throws IOException, ParseException {
        // check
        Assert.notNull(loginUser);
        UserLevel level = loginUser.getLevel();
        List<WithdrawExportVo> lst = null;
        long total = 0;
        // init
        ModelAndView view = createModelAndView("withdraw-lst");
        to = DateUtils.checkElseNow(to);
        if (StringUtils.isNotBlank(from)) {
            Assert.isTrue(from.matches(pattern), "指定开始日期格式有误，非 YYYY-MM-DD 形式");
        } else {
            from = to;
        }
        // query
        if (!level.equals(UserLevel.ADMIN)) {
            cpId = Long.valueOf(loginUser.getUsername());
        }
        total = withdrawLogicService.count(cpId,state, from, to);
        if (total > 0) {
            lst = withdrawLogicService.exportList(cpId,state, from, to, 1, 10000);
        }
        //1.初始化excel表格
        initExcel();
        //2.开始在excel表里面存入数据
        String[] tableHeader = new String[]{"ID","商户ID","商户名称","银行","支行","卡号","姓名","金额","手续费","到账金额","提现类型","代付类型","状态","备注"
                ,"申请时间","出款时间"};
        initParam("提现代付列表");
        daochu(lst,tableHeader);
        finishExcel("提现代付 列表",resp);

        return null;
    }


    @RequestMapping(value = "/{withdrawId:\\d+}", method = RequestMethod.GET)
    public ModelAndView get(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "withdrawId", required = true) Long withdrawId) {
        // check login
        Assert.notNull(loginUser);

        // init
        WithdrawVo withdraw = null;
        ModelAndView view = createModelAndView(0 == withdrawId ? "withdraw-apply" : "withdraw-detail");

        //
        if (null != withdrawId && 0 != withdrawId) {
            withdraw = withdrawLogicService.get(withdrawId);
        } else {
            withdraw = new WithdrawVo();
            withdraw.setId(0l);
            withdrawLogicService.initInfo(view, loginUser);
        }
        view.addObject("detail", withdraw);
        view.addObject("isHoliday", holidayService.check(new Date()));
        withdrawLogicService.fillApplyArgs(view, loginUser);

        //以下操作主要是为了避免刷新页面
        //清除缓存
        codeCacheUtils.invalidateCode(loginUser.getUsername(),AliyunSMSTemplateEnum.MONYUNVALID.getCode());
        //验证码
        String validCode = codeCacheUtils.generateValidCode(loginUser.getUsername(), AliyunSMSTemplateEnum.MONYUNVALID.getCode());
        view.addObject("validCode", validCode);

        return view;
    }

    /**
     * 提现、代付申请
     * @param loginUser
     * @param withdraw
     * @return
     * @throws ParseException
     * @throws UnsupportedEncodingException
     */
    @RequestMapping(value = {"", "/"}, method = RequestMethod.POST)
    public ModelAndView save(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            WithdrawVo withdraw) throws ParseException, UnsupportedEncodingException {
        String from = DateUtils.checkElseNow("");
        String myValidCode = codeCacheUtils.getValidCode(loginUser.getUsername(),AliyunSMSTemplateEnum.MONYUNVALID.getCode());
        if(withdraw.getValidCode().equals(myValidCode)){
            //清除缓存
            codeCacheUtils.invalidateCode(loginUser.getUsername(),AliyunSMSTemplateEnum.MONYUNVALID.getCode());
        }else {
            return listByCpId(loginUser, null,(byte)-1, from, from, 1, 10);
        }

        // save
        withdrawLogicService.save(loginUser, withdraw);
        Long cpId = null;

        return listByCpId(loginUser, cpId,(byte)-1, from, from, 1, 10);
    }

    /**
     * 查询是否两分钟之内有验证码，有则拒绝发送
     * @param loginUser
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/queryValid", method = RequestMethod.PUT)
    public Result queryValid(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser) {
        Assert.notNull(loginUser);
        Cp cp = cpService.getOneById(Long.parseLong(loginUser.getUsername().equals("admin")?String.valueOf(loginUser.getPid()):loginUser.getUsername()));
        Assert.notNull(cp, "未找到指定 CP");
        String phone = cp.getBindMobile();
        String validCode = codeCacheUtils.getValidCode(phone, AliyunSMSTemplateEnum.MONYUNVALID.getCode());

        Result result = new Result<>();
        if(StringUtils.isBlank(validCode)){
            result.setCode(200);
        }else{
            result.setCode(-1);
        }
        return result;
    }

    @ResponseBody
    @RequestMapping(value = "/{withdrawId:\\d+}/cancel", method = RequestMethod.PUT)
    public Result cancel(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "withdrawId", required = true) Long withdrawId) {

        // init
        Result result = new Result<>();

        // logic
        try {
            withdrawLogicService.cancel(loginUser, withdrawId);
            result.setCode(200);
        } catch (Exception e) {
            result.setCode(-1);
            result.setMsg(e.getMessage());
        }

        return result;
    }

    @ResponseBody
    @RequestMapping(value = "/{withdrawId:\\d+}/unPass", method = RequestMethod.PUT)
    public Result unPass(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "withdrawId", required = true) Long withdrawId,
            @RequestParam(name = "remark", required = true) String remark) {
        // init
        Result result = new Result<>();
        // logic
        try {
            withdrawLogicService.unPass(loginUser, withdrawId, remark);
            result.setCode(200);
        } catch (Exception e) {
            result.setCode(-1);
            result.setMsg(e.getMessage());
        }

        return result;
    }

    @ResponseBody
    @RequestMapping(value = "/{withdrawId:\\d+}/handPass", method = RequestMethod.PUT)
    public Result handPass(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "withdrawId", required = true) Long withdrawId,
            @RequestParam(name = "remark", required = true) String remark) {

        // init
        Result result = new Result<>();

        // logic
        try {
            withdrawLogicService.handPass(loginUser, withdrawId, remark);
            result.setCode(200);
        } catch (Exception e) {
            result.setCode(-1);
            result.setMsg(e.getMessage());
        }

        return result;
    }

    @ResponseBody
    @RequestMapping(value = "/valid", method = RequestMethod.GET)
    public Result valid(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser) {
        // init
        Result result = new Result<>();
        // logic
        try {
            result.setData(withdrawLogicService.valid(loginUser));
            result.setCode(200);
        } catch (Exception e) {
            result.setCode(-1);
            result.setMsg(e.getMessage());
        }

        return result;
    }



    /**
     * 确认通过提现审核，代付（非手动出款）
     * @param loginUser
     * @param withdrawId
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/{withdrawId:\\d+}/pass", method = RequestMethod.PUT)
    public Result pass(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "withdrawId", required = true) Long withdrawId,
            @RequestParam(name = "agentNo", required = true) String agentNo,
            @RequestParam(value = "trxType", required = true, defaultValue = "") String trxType,
            @RequestParam(value = "accountType", required = true, defaultValue = "") String accountType) throws UnsupportedEncodingException {
        CpWithdrawTradlog cpWithdrawTradlog = withdrawService.get(withdrawId);

        Result result = new Result<>();

        return result;
    }

    /**
     * 代付接口，请求代付（管理员提现）
     */
    @RequestMapping(value = "/anotherApply",method = RequestMethod.POST,produces = {"application/xml;charset=UTF-8"})
    public ModelAndView anotherApply(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @RequestParam(value = "amount", required = true, defaultValue = "0") Double amount,
            @RequestParam(value = "accNo", required = true, defaultValue = "") String accNo,
            @RequestParam(value = "accName", required = true, defaultValue = "") String accName,
            @RequestParam(value = "bankCode", required = true, defaultValue = "") String bankCode
    ) throws Exception{

        Map<String, Object> spConfig = spConfigService.getKeyValues(BwmConfig.tt_spid);
        Map<String, Object> responseMap = withdrawAnotherService.anotherApply(spConfig,accNo,accName, bankCode,
                String.valueOf(new BigDecimal(String.valueOf(amount)).multiply(new BigDecimal("100")).intValue()));//向上游代付
        //CertUtil
        if (responseMap.get("Code") != null && responseMap.get("Code").toString().equals("00")) {
            //成功，跳转列表
            String from = DateUtils.checkElseNow("");
            return listByCpId(loginUser, null,(byte)-1, from, from, 1, 10);
        }else{
            //不成功,给出提示
            msg = responseMap.get("Desc").toString();
            return toAnotherApply(loginUser);
        }

    }

    /**
     * 查询代付通道的余额
     * @param loginUser
     * @param agentNo
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/queryCh", method = RequestMethod.PUT)
    public Result queryCh(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @RequestParam(name = "agentNo", required = true) String agentNo,
            @RequestParam(name = "accountType", required = true) String accountType) {
        Map<String, Object> spConfig = spConfigService.getKeyValues(BwmConfig.tt_spid);
        Map<String, Object> responseMap = withdrawAnotherService.findDfBalance(spConfig,"");
        Result result = new Result<>();
        if(responseMap!=null){
            result.setCode(200);
            result.setData(responseMap.get("balance"));
        }else{
            result.setCode(-1);
            result.setMsg("请求失败");
        }
        return result;
    }

    private Map<Byte, String> mapState() {
        // init
        Map<Byte, String> map = new TreeMap<>();

        // fill
        for (WithdrawStateEnum p : WithdrawStateEnum.values()) {
            map.put(p.getState(), p.getInfo());
        }
        map.put((byte)-1,"所有");
        //
        map.remove((byte)1);
        map.remove((byte)3);
        map.remove((byte)4);
        map.remove((byte)2);

        map.put((byte)2,"成功");
        map.put((byte)-2,"失败");
        return map;
    }




    /**
     * 合付提现--代付
     * @param loginUser
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/toAnotherApply", method = RequestMethod.GET)
    public ModelAndView toAnotherApply(@AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser) throws Exception {

        ModelAndView view = createModelAndView("another-apply");
        view.addObject("level",UserLevel.ADMIN);
        Map<String, Object> spConfig = spConfigService.getKeyValues(BwmConfig.tt_spid);
        Map<String, Object> qqResponseMap = withdrawAnotherService.findDfBalance(spConfig,"QQ");
        if(qqResponseMap!=null&&"00".equals(qqResponseMap.get("Code"))){
//            AllBalance/AllBrawableBalance
            view.addObject("QQAllBalance",new BigDecimal(String.valueOf(qqResponseMap.get("AllBalance"))).divide(new BigDecimal("100")));
            view.addObject("QQAllBrawableBalance",new BigDecimal(String.valueOf(qqResponseMap.get("AllBrawableBalance"))).divide(new BigDecimal("100")));
        }

        Map<String, Object> wxResponseMap = withdrawAnotherService.findDfBalance(spConfig,"WEIXIN");
        if(wxResponseMap!=null&&"00".equals(wxResponseMap.get("Code"))){
//            AllBalance/AllBrawableBalance
            view.addObject("WxAllBalance",new BigDecimal(String.valueOf(wxResponseMap.get("AllBalance"))).divide(new BigDecimal("100")));
            view.addObject("WxAllBrawableBalance",new BigDecimal(String.valueOf(wxResponseMap.get("AllBrawableBalance"))).divide(new BigDecimal("100")));
        }
        if(msg!=null){
            view.addObject("msg",msg);
            msg = null;
        }

        return view;
    }


    /**
     * 打开提现申请菜单
     * @param loginUser
     * @param loginUser
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/preWithdraw", method = RequestMethod.GET)
    public ModelAndView preWithdraw(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser
            ) {
        ModelAndView view = createModelAndView("withdrawPre");
        // check login
        Assert.notNull(loginUser);

        // init
        WithdrawVo withdraw = null;

        withdraw = new WithdrawVo();
        withdraw.setId(0l);
        withdrawLogicService.initInfo(view, loginUser);
        view.addObject("detail", withdraw);
        view.addObject("isHoliday", holidayService.check(new Date()));
        withdrawLogicService.fillApplyArgs(view, loginUser);

        //以下操作主要是为了避免刷新页面
        //清除缓存
        codeCacheUtils.invalidateCode(loginUser.getUsername(),AliyunSMSTemplateEnum.MONYUNVALID.getCode());
        //验证码
        String validCode = codeCacheUtils.generateValidCode(loginUser.getUsername(), AliyunSMSTemplateEnum.MONYUNVALID.getCode());
        view.addObject("validCode", validCode);
        return view;
    }

    /**
     * 新提现提交
     * @param loginUser
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/withdrawSubmit", method = RequestMethod.POST)
    public ModelAndView WithdrawSubmit(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @RequestParam(value = "cpId", required = false, defaultValue = "") Long cpId,
            @RequestParam(value = "state", required = false, defaultValue = "") Byte state,
            @RequestParam(value = "from", required = false, defaultValue = "") String from,
            @RequestParam(value = "to", required = false, defaultValue = "") String to,
            @RequestParam(value = "p", required = false, defaultValue = "1") int p,
            @RequestParam(value = "pz", required = false, defaultValue = "10") int pz) throws ParseException, UnsupportedEncodingException {


        ModelAndView view = createModelAndView("withdrawPre");
        view.addObject("addSuccess", true);
        return view;
    }
}
